#include "serializer/io.h"
#include "serializer/serializer.h"

#include <gtest/gtest.h>

#include <string>

using namespace serializer;

// ============================================================================
// 测试场景 1：仅提供 ADL 自由函数 serialize_value / deserialize_value
// 验证：统一 CPO 会选择 ADL 路径，往返序列化成功
// ============================================================================
namespace user_models_ff
{
struct FreeFuncType
{
    int value;
    std::string name;
    bool operator==(const FreeFuncType & other) const
    {
        return value == other.value && name == other.name;
    }
};

static bool s_adl_serialize_used = false;
static bool s_adl_deserialize_used = false;

/**
 * 为 FreeFuncType 提供 ADL 自由函数序列化实现
 * 参数:
 * - writer 写入器，满足 writer 概念
 * - v 需要序列化的对象
 * - options 序列化选项
 * 返回值: 无
 * 异常: 由底层 writer 或序列化逻辑抛出
 */
template <typename Writer,
          typename Options,
          typename std::enable_if<serializer::writer<Writer> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
void
serialize_value(Writer & writer, const FreeFuncType & v, const Options & options)
{
    s_adl_serialize_used = true;
    // 复用默认实现序列化基础类型，确保 options 生效（如字节序）
    tag_invoke_fn(serialize_tag, writer, v.value, options);
    tag_invoke_fn(serialize_tag, writer, v.name, options);
}

/**
 * 为 FreeFuncType 提供 ADL 自由函数反序列化实现
 * 参数:
 * - reader 读取器，满足 reader 概念
 * - options 序列化选项
 * - tag 类型标签（由 CPO 传入，用于指明目标类型）
 * 返回值: 反序列化得到的 FreeFuncType 对象
 * 异常: 由底层 reader 或序列化逻辑抛出
 */
template <typename Reader,
          typename Options,
          typename std::enable_if<serializer::reader<Reader> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
FreeFuncType
deserialize_value(Reader & reader, const Options & options, type_tag_t<FreeFuncType>)
{
    s_adl_deserialize_used = true;
    FreeFuncType out{};
    out.value = tag_invoke_fn(deserialize_tag<int>, reader, options);
    out.name = tag_invoke_fn(deserialize_tag<std::string>, reader, options);
    return out;
}
} // namespace user_models_ff

TEST(cpo_adl_free_functions_test, adl_free_functions_are_used_when_available)
{
    vector_writer writer;
    default_options options{};

    user_models_ff::s_adl_serialize_used = false;
    user_models_ff::s_adl_deserialize_used = false;

    user_models_ff::FreeFuncType original{0x01020304, "alpha"};
    serialize(writer, original, options);
    EXPECT_TRUE(user_models_ff::s_adl_serialize_used);

    vector_reader reader(writer.data());
    auto deserialized = deserialize<user_models_ff::FreeFuncType>(reader, options);
    EXPECT_TRUE(user_models_ff::s_adl_deserialize_used);
    EXPECT_EQ(original, deserialized);
}

// ============================================================================
// 测试场景 2：同时提供 tag_invoke 与 ADL 自由函数
// 验证：CPO 优先级选择 tag_invoke（高于 ADL）
// ============================================================================
namespace user_models_both
{
struct BothPathsType
{
    int value;
    bool operator==(const BothPathsType & other) const { return value == other.value; }
};

static bool s_tag_invoke_serialize_used = false;
static bool s_tag_invoke_deserialize_used = false;
static bool s_adl_serialize_used = false;
static bool s_adl_deserialize_used = false;

/**
 * tag_invoke 的序列化实现（应被 CPO 优先选择）
 * 参数:
 * - writer 写入器
 * - v 序列化对象
 * - options 序列化选项
 * 返回值: 无
 * 异常: 由底层 writer 或序列化逻辑抛出
 */
template <typename Writer,
          typename Options,
          typename std::enable_if<serializer::writer<Writer> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
void
tag_invoke(serialize_tag_t, Writer & writer, const BothPathsType & v, const Options & options)
{
    s_tag_invoke_serialize_used = true;
    tag_invoke_fn(serialize_tag, writer, v.value, options);
}

/**
 * ADL 自由函数序列化实现（存在但不应被选择）
 * 参数:
 * - writer 写入器，满足 writer 概念
 * - v 需要序列化的对象
 * - options 序列化选项
 * 返回值: 无
 * 异常: 由底层 writer 或序列化逻辑抛出
 */
template <typename Writer,
          typename Options,
          typename std::enable_if<serializer::writer<Writer> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
void
serialize_value(Writer & writer, const BothPathsType & v, const Options & options)
{
    s_adl_serialize_used = true;
    tag_invoke_fn(serialize_tag, writer, v.value, options);
}

/**
 * tag_invoke 的反序列化实现（应被 CPO 优先选择）
 * 参数:
 * - reader 读取器，满足 reader 概念
 * - options 序列化选项
 * 返回值: 反序列化得到的 BothPathsType 对象
 * 异常: 由底层 reader 或序列化逻辑抛出
 */
template <typename Reader,
          typename Options,
          typename std::enable_if<serializer::reader<Reader> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
BothPathsType
tag_invoke(deserialize_tag_t<BothPathsType>, Reader & reader, const Options & options)
{
    s_tag_invoke_deserialize_used = true;
    BothPathsType out{};
    out.value = tag_invoke_fn(deserialize_tag<int>, reader, options);
    return out;
}

/**
 * ADL 自由函数反序列化实现（存在但不应被选择）
 * 参数:
 * - reader 读取器，满足 reader 概念
 * - options 序列化选项
 * - tag 类型标签（由 CPO 传入，用于指明目标类型）
 * 返回值: 反序列化得到的 BothPathsType 对象
 * 异常: 由底层 reader 或序列化逻辑抛出
 */
template <typename Reader,
          typename Options,
          typename std::enable_if<serializer::reader<Reader> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
BothPathsType
deserialize_value(Reader & reader, const Options & options, type_tag_t<BothPathsType>)
{
    s_adl_deserialize_used = true;
    BothPathsType out{};
    out.value = tag_invoke_fn(deserialize_tag<int>, reader, options);
    return out;
}
} // namespace user_models_both

TEST(cpo_adl_free_functions_test, tag_invoke_has_higher_priority_than_adl_free_functions)
{
    vector_writer writer;
    default_options options{};

    user_models_both::s_tag_invoke_serialize_used = false;
    user_models_both::s_tag_invoke_deserialize_used = false;
    user_models_both::s_adl_serialize_used = false;
    user_models_both::s_adl_deserialize_used = false;

    user_models_both::BothPathsType original{42};
    serialize(writer, original, options);
    vector_reader reader(writer.data());
    auto deserialized = deserialize<user_models_both::BothPathsType>(reader, options);

    EXPECT_TRUE(user_models_both::s_tag_invoke_serialize_used);
    EXPECT_TRUE(user_models_both::s_tag_invoke_deserialize_used);
    EXPECT_FALSE(user_models_both::s_adl_serialize_used);
    EXPECT_FALSE(user_models_both::s_adl_deserialize_used);
    EXPECT_EQ(original, deserialized);
}

// ============================================================================
// 测试场景 3：错误命名空间中的自由函数不被 ADL 绑定
// 验证：仅同类型命名空间中的自由函数才会被拾取
// ============================================================================
namespace ns_a
{
struct WrongNsType
{
    int value;
    bool operator==(const WrongNsType & other) const { return value == other.value; }
};

// 提供 tag_invoke，使类型可被序列化（避免测试因不可序列化而编译失败）
/**
 * 为 WrongNsType 提供 tag_invoke 的序列化实现（用于确保类型可参与测试）
 * 参数:
 * - writer 写入器，满足 writer 概念
 * - v 需要序列化的对象
 * - options 序列化选项
 * 返回值: 无
 * 异常: 由底层 writer 或序列化逻辑抛出
 */
template <typename Writer,
          typename Options,
          typename std::enable_if<serializer::writer<Writer> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
void
tag_invoke(serialize_tag_t, Writer & writer, const WrongNsType & v, const Options & options)
{
    tag_invoke_fn(serialize_tag, writer, v.value, options);
}

/**
 * 为 WrongNsType 提供 tag_invoke 的反序列化实现（用于确保类型可参与测试）
 * 参数:
 * - reader 读取器，满足 reader 概念
 * - options 序列化选项
 * 返回值: 反序列化得到的 WrongNsType 对象
 * 异常: 由底层 reader 或序列化逻辑抛出
 */
template <typename Reader,
          typename Options,
          typename std::enable_if<serializer::reader<Reader> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
WrongNsType
tag_invoke(deserialize_tag_t<WrongNsType>, Reader & reader, const Options & options)
{
    WrongNsType out{};
    out.value = tag_invoke_fn(deserialize_tag<int>, reader, options);
    return out;
}
} // namespace ns_a

namespace ns_b
{
static bool s_unrelated_adl_serialize_used = false;
static bool s_unrelated_adl_deserialize_used = false;

/**
 * 无关命名空间中的自由函数（用于负例断言，不应被 ADL 选中）
 * 参数:
 * - writer 写入器（未使用）
 * - v 需要序列化的对象（未使用）
 * - options 序列化选项（未使用）
 * 返回值: 无
 * 异常: 无（此函数仅用于记录是否被误选）
 */
template <typename Writer,
          typename Options,
          typename std::enable_if<serializer::writer<Writer> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
void
serialize_value(Writer & /*writer*/, const ns_a::WrongNsType & /*v*/, const Options & /*options*/)
{
    s_unrelated_adl_serialize_used = true; // 若被调用，将置位
}

/**
 * 无关命名空间中的自由函数（用于负例断言，不应被 ADL 选中）
 * 参数:
 * - reader 读取器（未使用）
 * - options 序列化选项（未使用）
 * - tag 类型标签（未使用）
 * 返回值: 返回一个默认构造的 WrongNsType（未使用）
 * 异常: 无（此函数仅用于记录是否被误选）
 */
template <typename Reader,
          typename Options,
          typename std::enable_if<serializer::reader<Reader> &&
                                      serializer::serialization_options<Options>,
                                  int>::type = 0>
ns_a::WrongNsType
deserialize_value(Reader & /*reader*/, const Options & /*options*/, type_tag_t<ns_a::WrongNsType>)
{
    s_unrelated_adl_deserialize_used = true; // 若被调用，将置位
    return ns_a::WrongNsType{};
}
} // namespace ns_b

TEST(cpo_adl_free_functions_test, adl_does_not_pick_functions_from_unrelated_namespaces)
{
    vector_writer writer;
    default_options options{};

    ns_b::s_unrelated_adl_serialize_used = false;
    ns_b::s_unrelated_adl_deserialize_used = false;

    ns_a::WrongNsType original{2024};
    serialize(writer, original, options);
    vector_reader reader(writer.data());
    auto deserialized = deserialize<ns_a::WrongNsType>(reader, options);

    EXPECT_FALSE(ns_b::s_unrelated_adl_serialize_used);
    EXPECT_FALSE(ns_b::s_unrelated_adl_deserialize_used);
    EXPECT_EQ(original, deserialized);
}

// ============================================================================
// 测试场景 4：占位锚点不影响 ADL 检测（概念为假）
// 验证：serializer 命名空间中的 requires(false) 占位不会导致 has_adl_* 概念为真
// ============================================================================
namespace compile_time_checks
{
struct NoCustomPathType
{
    int value;
};
} // namespace compile_time_checks

TEST(cpo_adl_free_functions_test, adl_placeholders_do_not_make_has_adl_true)
{
    // 对于内置类型与未提供自由函数的类型，has_adl_* 应为 false
    static_assert(!has_adl_serialize<int, vector_writer, default_options>);
    static_assert(!has_adl_deserialize<int, vector_reader, default_options>);

#if defined(__cpp_concepts)
    static_assert(
        !has_adl_serialize<compile_time_checks::NoCustomPathType, vector_writer, default_options>);
    static_assert(!has_adl_deserialize<compile_time_checks::NoCustomPathType,
                                       vector_reader,
                                       default_options>);
#endif
}

// ============================================================================
// 测试场景 5：验证 options 在 ADL 自由函数路径中的传递与生效（字节序）
// ============================================================================
TEST(cpo_adl_free_functions_test, options_are_respected_in_adl_free_functions)
{
    vector_writer writer;
    default_options options{};

    auto little = options.with_byte_order(byte_order::little_endian);
    auto big = options.with_byte_order(byte_order::big_endian);

    user_models_ff::s_adl_serialize_used = false;
    user_models_ff::s_adl_deserialize_used = false;

    user_models_ff::FreeFuncType value_le{0x01020304, "le"};
    serialize(writer, value_le, little);
    vector_reader reader_le(writer.data());
    auto out_le = deserialize<user_models_ff::FreeFuncType>(reader_le, little);
    EXPECT_TRUE(user_models_ff::s_adl_serialize_used);
    EXPECT_TRUE(user_models_ff::s_adl_deserialize_used);
    EXPECT_EQ(out_le, value_le);

    // 切换字节序后重新序列化，确保反序列化仍与原值一致
    writer.clear();
    user_models_ff::s_adl_serialize_used = false;
    user_models_ff::s_adl_deserialize_used = false;

    user_models_ff::FreeFuncType value_be{0x01020304, "be"};
    serialize(writer, value_be, big);
    vector_reader reader_be(writer.data());
    auto out_be = deserialize<user_models_ff::FreeFuncType>(reader_be, big);
    EXPECT_TRUE(user_models_ff::s_adl_serialize_used);
    EXPECT_TRUE(user_models_ff::s_adl_deserialize_used);
    EXPECT_EQ(out_be, value_be);
}